package com.engine.salary.formlua.func.logic;

import com.alibaba.fastjson.JSONObject;
import com.engine.salary.formlua.entity.parameter.DataType;
import com.engine.salary.formlua.entity.parameter.FuncNames;
import com.engine.salary.formlua.util.ErrorUtil;
import com.engine.salary.formlua.util.ExcelParamUtil;
import com.engine.salary.formlua.util.IgnoreParamFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @className：
 * @Description：Excel逻辑函数
 * @Author：
 * @date：
 */
public class LogicServiceImpl implements LogicService {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Boolean not(Object... objects) {
        DataType resultdataType = new DataType();
        resultdataType.setDataType(DataType.BOOL);
        Class[] typeObjects = new Class[]{boolean.class};
        IgnoreParamFilter.commonFilter("NOT", 1, 1, typeObjects, objects);
        Object object = objects[0];
        if (object == null) {
            resultdataType.setContent(false);
            return false;
        }
        Boolean cnd;
        if (object instanceof DataType) {
            DataType dataType = (DataType) object;
            cnd = dataType.getContent() != null ? ((Boolean) dataType.getContent()) : false;
        } else {
            cnd = (boolean) object;
        }

        resultdataType.setContent(!cnd);
        return (Boolean) resultdataType.getContent();
    }

    @Override
    public Boolean isEmpty(Object... objs) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.ISEMPTY.toString());
        if (objs.length != 1) {
            throw new RuntimeException("ISEMPTY函数只允许一个参数");
        }
        boolean result = false;
        if (null == objs || objs.length == 0) {
            DataType dataType = new DataType();
            dataType.setDataType(DataType.BOOL);
            dataType.setContent(true);
            return true;
        }
        for (int i = 0; i < objs.length; i++) {
            Object obj = objs[i];
            if (obj == null) {
                DataType dataType = new DataType();
                dataType.setDataType(DataType.BOOL);
                dataType.setContent(true);
                return true;
            }
            if (obj instanceof DataType) {
                DataType objDataType = (DataType) obj;
                if (objDataType.getDataType().equalsIgnoreCase(DataType.NUMBER)) {
                    Object numberContent = objDataType.getContent();
                    if (numberContent == null || numberContent.toString().equalsIgnoreCase("")) {
                        result = true;
                        break;
                    }
                }
            }
            obj = ExcelParamUtil.getParamContent(obj, "");
            if (null == obj || null == ExcelParamUtil.getParamContent(obj, "") || ExcelParamUtil.getParamContent(obj, "").equals("")) {
                result = true;
                break;
            }
        }
        DataType dataType = new DataType();
        dataType.setDataType(DataType.BOOL);
        dataType.setContent(result);
        return result;
    }

    @Override
    public Boolean isTrue(Object... objects) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.TRUE.toString());
        if (objects.length > 0) {
            throw new RuntimeException("TRUE函数不能有参数");
        }
        DataType dataType = new DataType();
        dataType.setDataType(DataType.BOOL);
        dataType.setContent(true);
        return (Boolean) dataType.getContent();
    }

    @Override
    public Boolean isFalse(Object... objects) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.FALSE.toString());
        if (objects.length > 0) {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.FALSE.toString(), number, number, "FALSE函数不能有参数");
            throw new RuntimeException(errorJson.getString("msg"));
        }
        DataType dataType = new DataType();
        dataType.setDataType(DataType.BOOL);
        dataType.setContent(false);
        return (Boolean) dataType.getContent();
    }


    @Override
    public DataType and(Object... objs) {
        IgnoreParamFilter.filterLogicAndORFunc(objs, "AND");
        Object result;
        int trueCount = 0;
        int falseCount = 0;
        DataType dataType = new DataType();
        for (int i = 0; i < objs.length; i++) {
            boolean bool;
            if (objs[i] instanceof DataType) {
                DataType paramdataType = (DataType) objs[i];
                bool = paramdataType.getContent() != null ? ((Boolean) paramdataType.getContent()) : false;
                //如果参数存在底层Logic运算，把运算记录加入到当前AND函数的运算记录中
                if (paramdataType.getSubLogic() != null && paramdataType.getSubLogic().size() > 0) {
                    dataType.getSubLogic().addAll(paramdataType.getSubLogic());
                }
            } else {
                bool = (boolean) objs[i];
            }

            if (bool) {
                trueCount++;
            } else {
                falseCount++;
            }
        }
        if (trueCount == objs.length) {
            result = true;
        } else {
            result = false;
        }

        dataType.setDataType(DataType.BOOL);
        dataType.setContent(result);
        dataType.getSubLogic().add("and");

        LogicUtils.buildAndOrFilterParam("AND", dataType, objs);
        return dataType;
    }

    @Override
    public DataType or(Object... objs) {
        IgnoreParamFilter.filterLogicAndORFunc(objs, "OR");
        Object result;
        int trueCount = 0;
        int falseCount = 0;
        DataType dataType = new DataType();
        for (int i = 0; i < objs.length; i++) {
            boolean bool;
            if (objs[i] instanceof DataType) {
                DataType paramdataType = (DataType) objs[i];
                bool = paramdataType.getContent() != null ? ((Boolean) paramdataType.getContent()) : false;
                //如果参数存在底层Logic运算，把运算记录加入到当前AND函数的运算记录中
                if (paramdataType.getSubLogic() != null && paramdataType.getSubLogic().size() > 0) {
                    dataType.getSubLogic().addAll(paramdataType.getSubLogic());
                }
            } else {
                bool = (boolean) objs[i];
            }
            if (bool) {
                trueCount++;
            } else {
                falseCount++;
            }
        }
        if (trueCount > 0) {
            result = true;
        } else {
            result = false;
        }

        dataType.setDataType(DataType.BOOL);
        dataType.setContent(result);
        dataType.getSubLogic().add("or");
        LogicUtils.buildAndOrFilterParam("OR", dataType, objs);
        return dataType;
    }


    @Override
    public DataType likeFunc(Object... objects) {
        IgnoreParamFilter.filterLikeFunc(objects);
        Object object = objects[0];
        Object result = false;
        String txtS = "";
        if (object instanceof DataType) {
            txtS = ExcelParamUtil.getParamContent(object, "string").toString();
        } else {
            txtS = object.toString();
        }
        if (null == txtS || txtS.trim().equals("")) {
            return new DataType(DataType.BOOL, false);
        }
        Object[] partamArray = (Object[]) objects[1];
        for (int i = 0; i < partamArray.length; i++) {
            Object cnd = partamArray[i];
            String cndStr = "";
            if (cnd instanceof DataType) {
                DataType cndJson = (DataType) cnd;
                cndStr = ExcelParamUtil.getParamContent(cndJson, "string").toString();
            } else {
                cndStr = cnd.toString();
            }

            int ridx = txtS.indexOf(cndStr);
            if (ridx >= 0 ? true : false) {
                result = ridx >= 0 ? true : false;
                break;
            }


        }
        DataType dataType = new DataType(DataType.BOOL, result);
        LogicUtils.buildLikeFilterParam(dataType, objects);
        return dataType;
    }

    @Override
    public DataType ifs(Object... objects) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.IFS.toString());
        if (objects.length == 0 || objects.length % 2 != 1 || objects.length < 3) {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.IFS.toString(), number, number, "IFS函数的参数必须大于3个且为单数");
            throw new RuntimeException(errorJson.getString("msg"));
        }
        int testI;
        for (testI = 1; testI <= objects.length; testI++) {
            if (testI % 2 > 0 && testI != objects.length) {
                Object cndObj = objects[testI - 1];
                if (!(cndObj instanceof Boolean) && !(cndObj instanceof DataType)) {
                    JSONObject errorJson = ErrorUtil.buildError(FuncNames.IFS.toString(), number, number, "IFS函数条件必须为真假值");
                    throw new RuntimeException(errorJson.getString("msg"));
                } else if (cndObj instanceof DataType) {
                    DataType boolDataType = (DataType) cndObj;
                    if (boolDataType.getContent() != null && !(boolDataType.getContent() instanceof Boolean)) {
                        JSONObject errorJson = ErrorUtil.buildError(FuncNames.IFS.toString(), number, number, "IFS函数条件必须为真假值");
                        throw new RuntimeException(errorJson.getString("msg"));
                    }
                }
            }
        }

        boolean paramCheck = checkParamType(objects);
        if (!paramCheck) {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.IFS.toString(), number, number, "IFS函数多个条件的返回值必须一致");
            throw new RuntimeException(errorJson.getString("msg"));
        }

        int i;
        for (i = 1; i <= objects.length; i++) {
            if (i % 2 == 0) {
                Object cndObj = objects[i - 2];
                if (cndObj instanceof Boolean) {
                    Boolean cnd = (Boolean) cndObj;
                    if (cnd) {
                        if (objects[i - 1] instanceof DataType) {
                            return (DataType) objects[i - 1];
                        } else {
                            return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i - 1].getClass().getName())), objects[i - 1]);
                        }
//						return new DataType(DataType.BOOL,objects[i-1]);
                    }
                } else if (cndObj instanceof DataType) {
                    DataType boolData = (DataType) cndObj;
                    Boolean cnd = boolData.getContent() != null ? ((Boolean) boolData.getContent()) : false;
                    if (cnd) {
                        if (objects[i - 1] instanceof DataType) {
                            return (DataType) objects[i - 1];
                        } else {
                            return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i - 1].getClass().getName())), objects[i - 1]);
                        }

                    }
                }
            }
        }
        //如果没有条件符合，返回默认值，最后一个参数为默认值
        Object result = ExcelParamUtil.getParamContent(objects[objects.length - 1], "");
        if (result instanceof DataType) {
            return (DataType) result;
        } else {
            return new DataType(DataType.returnType(ExcelParamUtil.getParamType(result.getClass().getName())), result);
        }

    }

    @Override
    public DataType find(Object... objects) {

        return new DataType(DataType.BOOL, finds(objects));
    }

    @Override
    public DataType switchs(Object... objects) {
        if (objects == null || objects.length == 0) {
            throw new RuntimeException("参数不能为空");
        }
        if (objects.length < 4) {
            throw new RuntimeException("switch函数的参数长度必须大于4个");
        }
        if (objects.length % 2 != 0) {
            throw new RuntimeException("switch函数的参数长度必须为双数");
        }
        Object source = objects[0];
        Object defaultValue = objects[objects.length - 1];
        if (source instanceof DataType) {
            source = ExcelParamUtil.getParamContent(source, "");
        }
        if (defaultValue instanceof DataType) {
            defaultValue = ExcelParamUtil.getParamContent(defaultValue, "");
        }
        Object result = null;
        for (int i = 1; i < objects.length - 1; i++) {
            if (i % 2 != 0) {
                Object param = objects[i];
                Object value = null;
                if (param instanceof DataType) {
                    value = ExcelParamUtil.getParamContent(param, "");
                } else {
                    value = param;
                }
                if (Objects.equals(source.toString(), value.toString())) {
                    result = objects[i + 1];
                    break;
                }
            }
        }
        if (result == null) {
            result = defaultValue;
        }


        return new DataType(DataType.BOOL, result);
    }

    public Boolean finds(Object... objects) {

        if (null == objects || objects.length < 2) {
            throw new RuntimeException("参数不能为空");
        }

        //获取查找类型 1：用第二个参数去第一个里面找。2：用第一个参数去第二个里面找
        String type = null;
        int vali = 2;
        if (objects.length >= 3) {
            if (objects[objects.length - 1] instanceof Integer) {
                vali = Integer.parseInt(objects[objects.length - 1].toString());
                if (vali != 1 && vali != 2) {
                    throw new RuntimeException("FIND函数第三个参数只允许1和2");
                }
            } else {
                throw new RuntimeException("FIND函数第三个参数只允许1和2");
            }
        }


        //将参数转换成List，要判断参数是数组还是单个对象
        List<Object> objs1 = null;
        List<Object> objs2 = null;
        if (objects[0] instanceof Object[]) {
            Object[] transObj = (Object[]) objects[0];
            objs1 = Arrays.asList(transObj);
        } else {
            objs1 = Arrays.asList(objects[0]);
        }
        if (objects[1] instanceof Object[]) {
            Object[] transObj = (Object[]) objects[1];
            objs2 = Arrays.asList(transObj);
        } else {
            objs2 = Arrays.asList(objects[1]);
        }


        if (objs1.size() == 0 || objs2.size() == 0) {
            throw new RuntimeException("参数不能为空");
        }

        //判断参数类型是否一致
        List<Object> all = new ArrayList<>();
        all.addAll(objs1);
        all.addAll(objs2);
        for (Object obj : all) {
            String localType = "";
            if (obj instanceof DataType) {
                String paramType = ExcelParamUtil.getParamType(obj);
                if (!paramType.toLowerCase().equals("option")) {
                    localType = ExcelParamUtil.checkParamType(paramType);
                } else {
                    localType = paramType;
                }
            } else {
                localType = ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(obj.getClass().getName()));
            }
            if (type == null) {
                type = localType;
            } else {
                if (!type.equalsIgnoreCase(localType)) {
                    throw new RuntimeException("参数类型不一致");
                }
            }
        }

        //根据超找类型判断谁是查找目标，谁是查找依据
        List<Object> targetList = new ArrayList<>();
        List<Object> keyList = new ArrayList<>();
        switch (vali) {
            case 1:
                targetList = transOptionData(objs1);
                keyList = transOptionData(objs2);
                break;
            case 2:
                targetList = transOptionData(objs2);
                keyList = transOptionData(objs1);
                break;
            default:
                throw new RuntimeException("查找类型错误");
        }

        for (Object keyO : keyList) {
            for (Object target : targetList) {
                if (keyO.equals(target)) {
                    return true;
                }
            }
        }

        return false;
    }

    private List<Object> transOptionData(List<Object> dataList) {
        List<Object> contentArrays = new ArrayList<>();
        for (Object data : dataList) {
            Object param1 = ExcelParamUtil.getParamContent(data, "");
            //获取依据数据的类型
            String keyType = "";
            if (data instanceof DataType) {
                keyType = ExcelParamUtil.getParamType(data);
            } else {
                keyType = ExcelParamUtil.getParamType(data.getClass().getName());
            }
            keyType = ExcelParamUtil.checkParamType(keyType);

            if (keyType.toLowerCase().equals(DataType.OPTION)) {
                contentArrays.addAll(Arrays.asList(param1.toString().split(",")));
            } else if (data instanceof Character) {
                contentArrays.add(param1.toString());
            } else if (keyType.toLowerCase().equals("number")) {
                contentArrays.add(Double.parseDouble(param1.toString()));
            } else {
                contentArrays.add(param1);
            }
        }
        return contentArrays;
    }

    private boolean checkParamType(Object[] objects) {
        boolean result = false;
        String type = null;
        for (int i = 1; i <= objects.length; i++) {
            if (i % 2 == 0) {
                Object obj = objects[i - 1];
                String typeStr = ExcelParamUtil.getParamType(obj);
                typeStr = ExcelParamUtil.checkParamType(typeStr);
                if (type == null) {
                    type = typeStr;
                } else {
                    result = typeStr.equalsIgnoreCase(type);
                    if (!result) {
                        return result;
                    }

                }
            }
        }
        String typeStr = ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(objects[objects.length - 1]));
        result = type.equalsIgnoreCase(typeStr);
        return result;
    }

}
